//Please run our Campus Map applet from the Model.java file.

package CampusMap.Model;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;




	//====================================================================================
	//GUI class
	//====================================================================================

	//An over-simplified GUI for drawing.
	@SuppressWarnings("serial") //Just to suppress a warning
	public class Model extends JPanel implements ActionListener, MouseListener, MouseMotionListener{

		//Member variables.
		private Point pnt;
		private ArrayList<Point> digList = new ArrayList<Point>();
		private ArrayList<POI> poiList = new ArrayList<POI>();
		protected int userX, userY;
		private static BufferedImage campus;
		private int mouseX, mouseY;
		private String modeStatus = "off";
		private poiInOut op1 = new poiInOut(poiList);
		private int curX=-1, curY=-1, poiIndex;
		private boolean inDrag = false;
		private int cursorStatus;
		//Create a file chooser
		final JFileChooser fc = new JFileChooser();
		


		
		
		//Constructor for MapMainProg.
		public Model() {
			
			//Calls the constructor of JPanel to enable DoubleBuffering to avoid flickering.
			super(true); 
			
			//Set the (preferred) size of the panel			
			setPreferredSize(new Dimension(699,446));
		}
		


		
	//====================================================================================
	//ACTIONS (CONTROL)
	//====================================================================================


		//Multi-listener using if-statements dependent upon the Jbutton clicked.
		public void actionPerformed(ActionEvent arg0){
				
			
			//Actions for clicking "Digitize Path" button.
			if (arg0.getActionCommand() == "Digitize Path"){

				//Print to console.
				System.out.println("");
				System.out.println("Switching modes ...");
				System.out.println("from: " + modeStatus);
	
				//Set status to "dig" (Digitize Path),
				//for use with overridden mouseRelease method.
				modeStatus = "dig";
				if (digList.size() > 0){
					ArrayList<Point> digList = new ArrayList<Point>();
					this.digList = digList;
				}			
				
				//Print to console.
				System.out.println("to: " + modeStatus);
								
				//Repaint the GUI.
				repaint();			
			}

			
			//Actions for clicking "Enter Points of Interest" button.
			if (arg0.getActionCommand() == "Create/Move POIs"){
				
				//Print to console.
				System.out.println("");
				System.out.println("Switching modes ...");
				System.out.println("from: " + modeStatus);
				
				//Set status to "poi" (Enter Points of Interest),
				//for use with overridden mouseRelease method.
				modeStatus = "poi";

				//Print to console.
				System.out.println("to: " + modeStatus);
		
				//Repaint the GUI.
				repaint();
			}
			
			if (arg0.getActionCommand() == "Load POIs"){

				//Show Open dialog
				int returnVal = fc.showOpenDialog(this);

				//Read array list of POIs from user-specified binary file.
		        if (returnVal == JFileChooser.APPROVE_OPTION) {
		            File file = fc.getSelectedFile();
		            poiList = op1.readFile(file);// This may need altering
		            
					System.out.println("");
					System.out.println("POIs loaded from data file:");
					System.out.println(file);
		        }
				//Repaint the GUI.
				repaint();
			}
			
			if (arg0.getActionCommand() == "Load Web POIs"){

				    poiList = op1.readFileWeb();
					System.out.println("");
					System.out.println("POIs loaded from the internet.");
					
		        }
				//Repaint the GUI.
				repaint();
			//}
			
			if (arg0.getActionCommand() == "Save POIs"){
				
				//Show Save dialog
				int returnVal = fc.showSaveDialog(this);
				
				//Write array list of POIs to user-specified binary file.
		        if (returnVal == JFileChooser.APPROVE_OPTION) {
		            File file = fc.getSelectedFile();
					op1.writeFile(poiList, file);// This may need altering
					System.out.println("");
					System.out.println("POIs saved to data file:");
					System.out.println(file);
		        }
				//Repaint the GUI.
				repaint();
			}		
			
		} //End ACTIONS
		
			
			

		

	//====================================================================================
	//PAINT (VIEW)
	//====================================================================================


		/*
		 * Java takes care of calling this method. For this reason we had to define MinimalDrawingGUI 
		 * as a subclass of JPanel (line 14). You do not need to call the method by hand. If, however, you
		 * change data in your model, e.g., the PointBuffer, you will have to call repaint().
		 * 
		 */
		public void paintComponent(Graphics g) {
	        super.paintComponent(g);    // Paints all other stuff, e..g., background. (Is this defined in JPanel?).
	        
	        // Cast to a Graphics2D object to support affine transformations.
	        Graphics2D g2d = (Graphics2D) g;
	        
	        //Draw the background campus map.
	        g2d.drawImage(campus, 0, 0, this);	   
	       	        	        
	        //Draw Digitized Path.
	        if (digList != null){
	        	
	        	//Draw Digitized Path Points.
	        	for (int i=0; i<digList.size(); i++){
	        		g2d.setColor(Color.blue);
	        		g2d.fillOval(
	        				(int) digList.get(i).getX()-4,
	        				(int) digList.get(i).getY()-4,
	        				(int) 2*4,
	        				(int) 2*4
	        				);
		        }
	        	
	        	//Draw Digitized Path lines if more than one Point.
	        	if (digList.size() > 1){
	        		for (int i=0; i < digList.size()-1; i++){
	        			g2d.drawLine(
	        					(int) digList.get(i).getX(),
	        					(int) digList.get(i).getY(),
	        					(int) digList.get(i+1).getX(),
	        					(int) digList.get(i+1).getY()
	        					);
	        		}
	        	}
	        }
		       	        
	        //Draw POIs. 
	        if (poiList != null){
	        	
	        	//Draw POI Points.
	        	for (int i=0; i<poiList.size(); i++){
	        		g2d.setColor(Color.red);
	        		g2d.fillOval(
	        				(int) poiList.get(i).getPt().getX()-4,
	        				(int) poiList.get(i).getPt().getY()-4,
	        				(int) 2*4,
	        				(int) 2*4
	        				);
	        	}
	        }
	       
	        //Draw POI Labels, if the Digitized Path Points are inside the POI PointBuffer.
	        for (int dig = 0; dig < digList.size(); dig++){
	        	for (int poi = 0; poi < poiList.size(); poi++){
	        		if (poiList.get(poi).isInside(digList.get(dig))) {
	        			//Create font.
	        			Font fontBold = new Font ("Helvetica", Font.BOLD, 16);
	        			//Set font.
	        			g2d.setFont(fontBold);
	        			//Draw Label.
	        			g2d.drawString(
	        					poiList.get(poi).getLabel().toString(),
	        					(int) poiList.get(poi).getPt().getX() + 6,
	        					(int) poiList.get(poi).getPt().getY() + 6
	        					);
	        		}
	        	}
	        }

	        
		} //End PAINT

		
		

				
	//====================================================================================
	//MAIN Program (embedded) (MODEL)
	//====================================================================================


		public static void main(String[] args) throws InterruptedException, IOException {

			System.out.println("Mike and Bo's Homework #9");
			System.out.println("=========================");
			
			//==================================================		
			//Create instance of MapMainProg class and add components.
			
			Model gui = new Model();
			
			//Add mouse listener and mouse motion listener
			gui.addMouseListener(gui);
			gui.addMouseMotionListener(gui);


			//Load the image (this time we do not handle the exception but throw it somewhere else ;-))
			campus = ImageIO.read(new File("C:\\java\\campus.png"));
			
			//adding menus and items
			JMenuBar menuBar = new JMenuBar();
			
			JMenu fileMenu = new JMenu("File");
			JMenu editMenu = new JMenu("Edit");
			
			JMenuItem LoadMenItem = new JMenuItem("Load POIs");
			JMenuItem LoadWebMenItem = new JMenuItem("Load Web POIs");
			JMenuItem SaveMenItem = new JMenuItem("Save POIs");			
			JMenuItem poiMenItem = new JMenuItem("Create/Move POIs");
			JMenuItem digMenItem = new JMenuItem("Digitize Path");
			
			//add menu to menubar
			menuBar.add(fileMenu);
			menuBar.add(editMenu);
			
			//add items to menus
			fileMenu.add(LoadMenItem);
			fileMenu.add(LoadWebMenItem);			
			fileMenu.add(SaveMenItem);
			editMenu.add(poiMenItem);
			editMenu.add(digMenItem);
			
				
			//adding action listeners for menu items
			digMenItem.addActionListener(gui);
			LoadMenItem.addActionListener(gui);
			LoadWebMenItem.addActionListener(gui);
			poiMenItem.addActionListener(gui);
			SaveMenItem.addActionListener(gui);
			
			//===========================
			//Default GUI settings (begin)
			//Frame size is still hard-coded with setPreferredSize().

			//Create JFrame to place other components such as panels or buttons within.
			JFrame frame = new JFrame("Campus Map: Points of Interest and Digitize Path");

			//Add an instance of the MinimalDrawingGUI to the frame.
			frame.add(gui);
			
			//Set the size, arrange components, and display the frame.
			frame.pack();
			frame.setVisible(true);
			
			//Exit on close.
			frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			
			//set menu in frame
			frame.setJMenuBar(menuBar);

			//Default GUI settings (end)
			//==========================

		
			
			
		} //End MAIN


		
		
	//====================================================================================
	//METHODS for MapMainProg class
	//====================================================================================	
	    
		//Override for the mouseReleased method.
		@Override
		public void mouseReleased(MouseEvent mUp) {
			
			//Get the mouse coordinates.
			mouseX =  mUp.getX();
			mouseY =  mUp.getY();
			
			//Actions if the "Digitize Path" button was pressed and the mouse button was released.
			if (modeStatus == "dig"){
				
				//Create Point from mouse coordinates.
				Point pnt = new Point((double) mouseX, (double) mouseY);
				
				//Add Point to the "Digitize Path" ArrayList.
				digList.add(pnt);
				
				//Print to console.
				System.out.println("");
				System.out.println("Digitized Path coordinates:");
				System.out.println(digList);				
			}
			
			//Actions if the "Enter Point of Interest" button was pressed and the mouse button was released.
			//But only if it's not a crosshair cursor
			if (modeStatus == "poi" & cursorStatus !=2){
				
				//Dialog box for user-specified Point of Interest name.
				String poiName = (String)JOptionPane.showInputDialog(
				                    null,
				                    "Enter a name for your Point of Interest.",
				                    "Point of Interest",
				                    JOptionPane.PLAIN_MESSAGE,
				                    null,
				                    null,
				                    null);
				
				
				//Create Point from mouse coordinates if string is not empty				
				if (poiName != null){
					Point pnt = new Point((double) mouseX, (double) mouseY);

					//Create POI from Point, hard-coded PointBuffer radius, Label.
					POI poi = new POI(pnt, (double) 8, poiName);

					//Add Point to the "Enter Point of Interest" ArrayList
					poiList.add(poi);

					//Print to console.
					System.out.println("");
					System.out.println("Points of Interest coordinates and name:");
					for (int i=0; i < poiList.size(); i++){
						System.out.println(poiList.get(i).getPt() + "   " + poiList.get(i).getLabel());	
						op1.setPoiListin(poiList);
					}				
					//if inDrag was set because you were dragging a poi, it now is unset
					inDrag = false;
				
					
				}		
			}	
			
			repaint();
			
		}
		
		@Override
		public void mouseClicked(MouseEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void mouseEntered(MouseEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void mouseExited(MouseEvent arg0) {
			// TODO Auto-generated method stub
			
		}

		@Override
		public void mousePressed(MouseEvent mousePress) {
			//if mode status is poi mode then we'll get the coords of the press
			if (modeStatus == "poi" & poiList.size() > 0){
				Point p = new Point(mousePress.getX(),mousePress.getY());
				
				//setting an index so we know which poi is going to get dragged
				for (int i=0; i <= poiList.size()-1; i++){
					if (poiList.get(i).isInside(p)){
						  poiIndex = i;
						break;
					}
				}
				//set flag that dragging might happen (used in the mouseDragged event) 
				inDrag = true;
			}
			
		}


		@Override
		public void mouseDragged(MouseEvent e) {
			//if statement so that the poi isn't moved during digitization
			if (modeStatus == "poi" & cursorStatus == 2){

				Point p = new Point(e.getX(),e.getY());


				curX = (int) p.getX();
				curY = (int) p.getY();
				if (inDrag) {
					poiList.get(poiIndex).getPt().setX(curX);
					poiList.get(poiIndex).getPt().setY(curY);

					//update file with new location
					op1.setPoiListin(poiList);	
					
					repaint();
				}
			}
		}
			
			
		




		@Override
		
		//defining the cursor type based on location compared to POI
		public void mouseMoved(MouseEvent evt) {
			
			Point p = new Point(evt.getX(),evt.getY());
		
		  for (int i=0; i <= poiList.size()-1; i++){
		    if (poiList.get(i).isInside(p)){
		      setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
		      //cursorStatus will drive what the user is able to do when clicking
		      cursorStatus=2;
		   
		      break;
		    }
		    else{
		      setCursor(Cursor.getDefaultCursor());
		      cursorStatus=1;
		      
		   
		    }
		  }
		    
		}
		
		
		//Getters and Setters for MapMainProg class
		
		public Point getPnt() {
			return pnt;
		}

		public void setPnt(Point pnt) {
			this.pnt = pnt;
		}
		
		public int getMouseX() {
			return mouseX;
		}

		public void setMouseX(int mouseX) {
			this.mouseX = mouseX;
		}

		public int getMouseY() {
			return mouseY;
		}

		public void setMouseY(int mouseY) {
			this.mouseY = mouseY;
		}




	


	  //End METHODS
		
			
	} //End MapMainProg CLASS



